#include "SerialPort.h"
#include "../../../../usr/include/asm-generic/ioctls.h"

SerialPort::SerialPort(std::string path,std::string baud_rate)
{
    device = path;
    //匹对波特率
    switch (std::stoi(baud_rate))
    {
    case 2400:
        baudRate = B2400;
        break;
    case 4800:
        baudRate = B4800;
        break;
    case 9600:
        baudRate = B9600;
        break;
    case 115200:
        baudRate = B115200;
        break;
    default:
        baudRate = B9600;
        break;
    }
    open_dev();
    config_dev(8,1,'N');

    // int wait_flag = noflag;
    // saio.sa_handler = signal_handler_IO;
    // sigemptyset (&saio.sa_mask);
    // saio.sa_flags = 0;
    // saio.sa_restorer = NULL;
    // sigaction (SIGIO, &saio, NULL);

}


SerialPort::~SerialPort()
{
    close_dev();
}

bool SerialPort::open_dev() {
    serial_port_fd = open(device.c_str(), O_RDWR |O_NONBLOCK);//| O_NOCTTY | O_NDELAY
    if (serial_port_fd < 0) {
        return false;
    }
    return true;
}

//配置串口函数
bool SerialPort::config_dev(){
    //配置串口
    tcgetattr(serial_port_fd, &options);

    //波特率设置
    cfsetispeed(&options, baudRate);
    cfsetospeed(&options, baudRate);
    // options.c_cflag = CLOCAL | CREAD | CS8;// 本地连接(不改变端口所有者)，接收使能 ，8为数据位
    (options.c_cflag &= ~CSIZE);
    (options.c_cflag |= CS8);// 8为数据位
    (options.c_cflag &= ~PARENB);//无奇偶校验
    (options.c_cflag &= ~CSTOPB);//停止位
    // options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    tcsetattr(serial_port_fd, TCSANOW, &options);//写入属性

    return true;
}

bool SerialPort::config_dev(int databits,int stopbits,int parity)
{ 
	struct termios options; 
	if  ( tcgetattr( serial_port_fd,&options)  !=  0) { 
		perror("SetupSerial 1");     
		return false;  
	}
	options.c_cflag &= ~CSIZE; 
	switch (databits) 
	{   
	case 7:		
		options.c_cflag |= CS7; 
		break;
	case 8:     
		options.c_cflag |= CS8;
		break;   
	default:    
		fprintf(stderr,"Unsupported data size\n"); return false;  
	}
	switch (parity) 
	{   
		case 'n':
		case 'N':    
			options.c_cflag &= ~PARENB;   /* Clear parity enable */
			options.c_iflag &= ~INPCK;     /* Enable parity checking */ 
			break;  
		case 'o':   
		case 'O':     
			options.c_cflag |= (PARODD | PARENB); 
			options.c_iflag |= INPCK;             /* Disnable parity checking */ 
			break;  
		case 'e':  
		case 'E':   
			options.c_cflag |= PARENB;     /* Enable parity */    
			options.c_cflag &= ~PARODD;    
			options.c_iflag |= INPCK;       /* Disnable parity checking */
			break;
		case 'S': 
		case 's':  /*as no parity*/   
		    options.c_cflag &= ~PARENB;
			options.c_cflag &= ~CSTOPB;break;  
		default:   
			fprintf(stderr,"Unsupported parity\n");    
			return false;  
		}  
	
	switch (stopbits)
	{   
		case 1:    
			options.c_cflag &= ~CSTOPB;  
			break;  
		case 2:    
			options.c_cflag |= CSTOPB;  
		   break;
		default:    
			 fprintf(stderr,"Unsupported stop bits\n");  
			 return false; 
	} 
	/* Set input parity option */ 
	if (parity != 'n')   
		options.c_iflag |= INPCK; 
	tcflush(serial_port_fd,TCIFLUSH);
	options.c_cc[VTIME] = 150; 
	options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
	if (tcsetattr(serial_port_fd,TCSANOW,&options) != 0)   
	{ 
		perror("SetupSerial 3");   
		return false;  
	} 
	return true;  
}

//获取串口配置
bool SerialPort::check_dev(){

    tcgetattr(serial_port_fd, &options);

    // 输出串口参数配置
    std::cout << "*****************************************************************" << std::endl;
    std::cout << "Serial port configuration:" << std::endl;
    std::cout << "  Baud rate(out): " << cfgetospeed(&options) << std::endl;
    std::cout << "  Baud rate(in) : " << cfgetispeed(&options) << std::endl;
    std::cout << "  Baud rate     : " << baudRate << std::endl;
    std::cout << "  c_cflag       : " << decimalToBinary(options.c_cflag) << std::endl;
    date_bits = (options.c_cflag & CSIZE);
    switch (date_bits)
    {
    case CS8:
        std::cout << "  Data bits: " << "8 bit" << std::endl;
        break;
    case CS7:
        std::cout << "  Data bits: " << "7 bit" << std::endl;
        break;
    case CS6:
        std::cout << "  Data bits: " << "6 bit" << std::endl;
        break;
    case CS5:
        std::cout << "  Data bits: " << "5 bit" << std::endl;
        break;
    
    default:
        std::cout << "  Data bits: " << "XXX" << std::endl;
        break;
    }
    std::cout << "  Stop bits: " << ((options.c_cflag & CSTOPB) ? "2 bit" : "1 bit") << std::endl;
    std::cout << "  Parity: " << ((options.c_cflag & PARENB) ? "enabled" : "disabled") << std::endl;
    std::cout << "  Parity type: " << ((options.c_cflag & PARODD) ? "odd" : "even") << std::endl;
    std::cout << "  Flow control: " << ((options.c_cflag & CLOCAL) ? "local" : "remote") << std::endl;
    std::cout << "*****************************************************************" << std::endl;

    return true;
}

void SerialPort::close_dev() {
    if (serial_port_fd >= 0) {
        close(serial_port_fd);
        serial_port_fd = -1;
    }
}

int SerialPort::readData(char *buffer, size_t len) {
    return read(serial_port_fd, buffer, len);
}

int SerialPort::readData_one(unsigned char *buffer) {
    return read(serial_port_fd, buffer, 1);
}


int SerialPort::writeData(const char *buffer, size_t len) {
    return write(serial_port_fd, buffer, len);
}

std::string SerialPort::decimalToBinary(unsigned int decimal) {
    std::string binary;
    while (decimal > 0) {
        binary = std::to_string(decimal % 2) + binary;
        decimal /= 2;
    }
    return binary;
}


// int SerialPort::check_dev_is_data(){
//     int bytesWaiting = 0;

//     ioctl(serial_port_fd, FIONREAD, &bytesWaiting);

//     return bytesWaiting;
// }
